﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using NSsh.Common.Types;
using System.IO;
using NSsh.Common.Packets;
using NUnit.Framework.SyntaxHelpers;
using NSsh.Common.Utility;

namespace NSsh.Common.Tests.Packets
{
    [TestFixture]
    public class PacketFixture
    {
        public static void ComparePacketByteData(Packet packet, MemoryStream stream)
        {
            byte[] packetArray = packet.ToByteArray();
            byte[] streamArray = stream.ToArray();

            byte packetPadding = packetArray[4];
            byte streamPadding = streamArray[4];

            byte[] packetArrayTrimmed = new byte[packetArray.Length - packetPadding - 5];
            byte[] streamArrayTrimmed = new byte[streamArray.Length - streamPadding - 5];

            Array.Copy(packetArray, 5, packetArrayTrimmed, 0, packetArrayTrimmed.Length);
            Array.Copy(streamArray, 5, streamArrayTrimmed, 0, streamArrayTrimmed.Length);

            Assert.That(packetArrayTrimmed, Is.EqualTo(streamArrayTrimmed));
        }

        [SetUp]
        public void Setup()
        {
            Dependency.Clear();
            Dependency.RegisterTransient<ISecureRandom, SecureRandom>("SecureRandom");
        }

        [Test]
        public void ShouldCreateFromPacketType()
        {
            PacketType packetType = PacketType.Debug;

            Packet packet = new TestPacket(packetType);

            Assert.That(packet.PacketType, Is.EqualTo(packetType), "Incorrect packet type.");
        }

        [Test]
        public void ShouldCreateFromBinaryReader()
        {
            int length = 123;
            int paddingLength = 5;
            byte[] randomPadding = { 0, 1, 2, 3, 4 };
            PacketType packetType = PacketType.Debug;
            MemoryStream memoryStream = new MemoryStream();

            BinaryWriter writer = new BinaryWriter(memoryStream);
            writer.WriteBE((uint)length);
            writer.Write((byte)paddingLength);
            writer.Write((byte)packetType);
            writer.Write(randomPadding);

            // Reset the stream
            memoryStream.Seek(0, SeekOrigin.Begin);

            // Create from the binary reader
            BinaryReader reader = new BinaryReader(memoryStream);
            Packet packet = new TestPacket(new SshPacketContext(reader));

            Assert.That(packet.PacketType, Is.EqualTo(packetType), "Incorrect packet type.");
            Assert.That(packet.RandomPadding, Is.EqualTo(randomPadding), "Incorrect packet random padding.");
        }

        [Test]
        public void ShouldReadFromStream()
        {
            IgnorePacket ignorePacket = new IgnorePacket();
            ignorePacket.Data = Encoding.ASCII.GetBytes("data");

            MemoryStream memoryStream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(memoryStream);
            writer.Write(ignorePacket.ToByteArray());

            // Reset the stream
            memoryStream.Seek(0, SeekOrigin.Begin);

            // Create from the binary reader
            Packet packet = new PacketFactory().ReadFrom(memoryStream, null, null, 0);

            Assert.That(packet.PacketType, Is.EqualTo(PacketType.Ignore), "Incorrect packet type.");
            Assert.That(packet, Is.InstanceOfType(typeof(IgnorePacket)), "Packet object is incorrect type.");
            Assert.That(((IgnorePacket) packet).Data, Is.EqualTo(ignorePacket.Data), "Packet data is incorrect.");
        }
    }

    class TestPacket : Packet
    {
        public TestPacket(PacketType packetType) : base(packetType) { }

        public TestPacket(SshPacketContext context) : base(context) { }

        protected override void InitialisePayload(BinaryReader reader) {}

        [CoverageExclude]
        public override byte[] GetPayloadData()
        {
            return new byte[0];
        }
    }
}
